#include "objecteditormode.h"
#include "editormodemanager.h"
#include "gameObjects/abstractgameobject.h"
#include "document.h"
#include "application.h"
#include "widgets/editorview.h"
#include "widgets/mainwindow.h"
#include "widgets/gameobjectseditorwidget.h"
#include "widgets/gameobjectpropertieswidget.h"
#include "editors/editormanager.h"

using namespace Modes;

ObjectEditorMode::ObjectEditorMode(EditorModeManager& em)
	: EditorMode("ObjectEditorMode", em)
{
	m_editorView = new EditorView(*this);
	connect(&Application::instance(), &Application::documentChanged, 
		m_editorView, &EditorView::onDocumentChanged);

	m_editorManager = new ObjectEditors::EditorManager(this);
 	connect(this, &ObjectEditorMode::documentChanged, 
 		m_editorManager, &ObjectEditors::EditorManager::onDocumentChanged);
	
	initDocks();
	initActions();
	initObjectToolbar();
	createConnections();
}

void Modes::ObjectEditorMode::enter()
{
	editorModeManager().mainWindow().setCentralWidget(m_editorView);
	m_gameObjectsDock->show();
	m_objectPropertiesDock->show();
	m_editorView->show();
	editorModeManager().mainWindow().reinitializeGui();
	editorModeManager().mainWindow().menuBar()->addMenu(m_objectMenu);
	m_objectToolbar->show();
}

void Modes::ObjectEditorMode::exit()
{
	editorModeManager().mainWindow().takeCentralWidget();
	m_gameObjectsDock->hide();
	m_objectPropertiesDock->hide();
	m_editorView->hide();
	editorModeManager().mainWindow().reinitializeGui();
	m_objectToolbar->hide();
}

void Modes::ObjectEditorMode::onDocumentChanged( QPointer<Document> doc )
{
	emit documentChanged(doc);

	if(!doc)
	{
		m_selectedObject = QPointer<AbstractGameObject>();
		// TODO: maybe to emit selectedObjectChanged()?
		m_editorManager->changeState(QPointer<AbstractState>());
	}

	updateGui();
	m_editorView->update();
}

void Modes::ObjectEditorMode::onAddActor()
{
	ACQUIRE_DOC();
	doc->createActor("");
}

void Modes::ObjectEditorMode::onAddVisualObject()
{
	ACQUIRE_DOC();
	QPointer<AbstractGameObject> actor = selectedGameObject();
	Q_ASSERT(actor && actor->type() == GOT_Actor);
	doc->createVisualObject("", actor);
}

void Modes::ObjectEditorMode::onAddPhysics()
{
	ACQUIRE_DOC();
	QPointer<AbstractGameObject> visualObject = selectedGameObject();
	Q_ASSERT(visualObject && visualObject->type() == GOT_VisualObject);
	doc->createPhysicsObject(visualObject);
}

void Modes::ObjectEditorMode::updateGui()
{
	ACQUIRE_DOC();
	if(doc)
	{
		QPointer<AbstractGameObject> selectedObject = selectedGameObject();
		m_addVisualObjectAct->setEnabled(selectedObject &&
			selectedObject->type() == GOT_Actor);
		// TODO: disable if already has collision data
		m_addPhysicsAct->setEnabled(selectedObject &&
			selectedObject->type() == GOT_VisualObject);	
	}
}

void Modes::ObjectEditorMode::onSelectedObjectChanged( QPointer<AbstractGameObject> gameObject )
{
	if(m_selectedObject != gameObject)
	{
		m_selectedObject = gameObject;
		emit selectedObjectChanged(m_selectedObject);

		if(!m_selectedObject)
		{
			m_editorManager->changeState(QPointer<AbstractState>());
		}
		else if(m_selectedObject->type() == GOT_Actor)
		{
			m_editorManager->changeState(QPointer<AbstractState>());
		}
		else if(m_selectedObject->type() == GOT_VisualObject)
		{
			m_editorManager->changeState("VisualObjectEditor");
		}
		else if(m_selectedObject->type() == GOT_PhysicsObject)
		{
			m_editorManager->changeState(QPointer<AbstractState>());
		}

		updateGui();
		m_editorView->update();
	}
}

QPointer<AbstractGameObject> Modes::ObjectEditorMode::selectedGameObject() const
{
	return m_selectedObject;
}

void Modes::ObjectEditorMode::initDocks()
{
	m_gameObjectsDock = new QDockWidget("Game Objects");
	m_gameObjectsDock->setAllowedAreas(Qt::LeftDockWidgetArea);
	GameObjectsEditorWidget* pGOEW = new GameObjectsEditorWidget(this);
	m_gameObjectsDock->setWidget(pGOEW);

	m_objectPropertiesDock = new QDockWidget("Object Properties");
	m_objectPropertiesDock->setAllowedAreas(Qt::RightDockWidgetArea);
	GameObjectPropertiesWidget* pGOPW = new GameObjectPropertiesWidget(this);
	m_objectPropertiesDock->setWidget(pGOPW);

	editorModeManager().mainWindow().addDockWidget(Qt::LeftDockWidgetArea, m_gameObjectsDock);
	editorModeManager().mainWindow().addDockWidget(Qt::RightDockWidgetArea, m_objectPropertiesDock);
	m_gameObjectsDock->hide();
	m_objectPropertiesDock->hide();
}

void Modes::ObjectEditorMode::initActions()
{
	m_objectMenu = new QMenu("Objects");
	m_addActorAct = m_objectMenu->addAction(QIcon("data/icons/addActor"), "Create Actor");
	m_addVisualObjectAct = m_objectMenu->addAction(QIcon("data/icons/addVisualObject"), "Add Visual");
	m_addPhysicsAct = m_objectMenu->addAction(QIcon("data/icons/addPhysics"), "Add Physics");
}

void Modes::ObjectEditorMode::initObjectToolbar()
{
	m_objectToolbar = new QToolBar;
	m_objectToolbar->setToolButtonStyle(Qt::ToolButtonTextUnderIcon);
	QFont otbFont = m_objectToolbar->font();
	otbFont.setPixelSize(9);
	m_objectToolbar->setFont(otbFont);
	m_objectToolbar->addAction(m_addActorAct);
	m_objectToolbar->addAction(m_addVisualObjectAct);
	m_objectToolbar->addAction(m_addPhysicsAct);
	editorModeManager().mainWindow().addToolBar(Qt::LeftToolBarArea, m_objectToolbar);
	m_objectToolbar->hide();
}

void Modes::ObjectEditorMode::createConnections()
{
	connect(m_addActorAct, &QAction::triggered, 
		this, &ObjectEditorMode::onAddActor);
	connect(m_addVisualObjectAct, &QAction::triggered, 
		this, &ObjectEditorMode::onAddVisualObject);
	connect(m_addPhysicsAct, &QAction::triggered, 
		this, &ObjectEditorMode::onAddPhysics);
}

QPointer<ObjectEditors::EditorManager> Modes::ObjectEditorMode::editorManager() const
{
	return m_editorManager;
}
